package com.ali.ding;

import static com.ding.rtc.DingRtcEngine.DingRtcVideoTrack.DingRtcVideoTrackCamera;
import static com.ding.rtc.DingRtcEngine.DingRtcVideoTrack.DingRtcVideoTrackScreen;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;
import android.view.SurfaceView;

import com.ding.rtc.DingRtcAuthInfo;
import com.ding.rtc.DingRtcEngine;
import com.ding.rtc.DingRtcEngineEventListener;

import java.util.HashMap;
import java.util.Map;

public class DingRtcManager extends DingRtcEngineEventListener {

    private static final String TAG = "DingRtcEngine";
    private static final DingRtcManager sInstance = new DingRtcManager();

    public static DingRtcManager getInstance() {
        return sInstance;
    }

    private DingRtcEngine mRtcEngine;
    private Handler sUiThreadHandler;
    private DingRtcPlugin mPlugin;
    private SparseArray<DingRtcView> mDingRtcViews;

    public void init(Context context, DingRtcPlugin plugin, String extra) {
        mPlugin = plugin;
        if(mRtcEngine != null) return;

        mDingRtcViews = new SparseArray<>();
        mRtcEngine = DingRtcEngine.create(context.getApplicationContext(), extra);
        mRtcEngine.subscribeAllRemoteAudioStreams(true);
        mRtcEngine.subscribeAllRemoteVideoStreams(true);
        mRtcEngine.setRemoteDefaultVideoStreamType(DingRtcEngine.DingRtcVideoStreamType.DingRtcVideoStreamTypeFHD);
        mRtcEngine.setRtcEngineEventListener(this);

        sUiThreadHandler = new Handler(Looper.getMainLooper());
    }

    private boolean runningOnUiThread() {
        return Looper.myLooper() == Looper.getMainLooper();
    }

    public void runOnUiThread(Runnable r) {
        if (runningOnUiThread()) {
            r.run();
        } else {
            sUiThreadHandler.post(r);
        }
    }

    public void destroy() {
        mPlugin = null;
        mRtcEngine.setRtcEngineEventListener(null);
        mRtcEngine.destroy();
        mRtcEngine = null;
        sUiThreadHandler = null;
    }

    public SurfaceView createRenderSurfaceView(Context context) {
        return mRtcEngine.createRenderSurfaceView(context);
    }

    private void callback(String method, Object args) {
        if(mPlugin != null) mPlugin.callBackToFlutter(method, args);
    }
    public void onError(int result, String reason) {
        runOnUiThread(() -> {
            Map map = new HashMap();
            map.put("code", result);
            map.put("message", reason);
            callback("onError", map);
        });
    }

    @Override
    public void onJoinChannelResult(int result, String channel, String userId, int elapsed){
        if(result == 0) {
            mRtcEngine.publishLocalVideoStream(true);
            mRtcEngine.publishLocalAudioStream(true);
        }
        runOnUiThread(() -> {
            Map map = new HashMap();
            map.put("result", result);
            map.put("channel", channel);
            map.put("userId", userId);
            map.put("elapsed", elapsed);
            callback("onJoinChannelResult", map);
        });
    }

    @Override
    public void onSnapshotComplete(String uid, DingRtcEngine.DingRtcVideoTrack videoTrack, String path, boolean success) {
        runOnUiThread(() -> {
            Map map = new HashMap();
            map.put("videoTrack", videoTrack.getValue());
            map.put("success", success);
            map.put("userId", uid);
            map.put("filePath", path);
            callback("onSnapshotComplete", map);
        });
    }

    public void onLeaveChannelResult(int result, DingRtcEngine.DingRtcStats stats){
        runOnUiThread(() -> {
//            Map map = new HashMap();
//            map.put("result", result);
//            map.put("stats", stats);
            callback("onLeaveChannelResult", result);
        });
    }

    public void onRemoteUserOnLineNotify(String uid, int elapsed){
        runOnUiThread(() -> {
            callback("onRemoteUserEnterRoom", uid);
        });
    }

    public void onRemoteUserOffLineNotify(String uid, DingRtcEngine.DingRtcUserOfflineReason reason){
        runOnUiThread(() -> {
            Map map = new HashMap();
            map.put("userId", uid);
            map.put("reason", reason.getValue());
            callback("onRemoteUserLeaveRoom", map);
        });
    }

    public void onRemoteTrackAvailableNotify(String uid, DingRtcEngine.DingRtcAudioTrack audioTrack, DingRtcEngine.DingRtcVideoTrack videoTrack){
        runOnUiThread(() -> {
            Map map = new HashMap();
            map.put("userId", uid);
            map.put("video", videoTrack.getValue());
            map.put("audio", audioTrack.getValue());
            callback("onRemoteStateUpdated", map);
        });
    }

    public void addView(int viewId, DingRtcView view) {
        if(mDingRtcViews.indexOfKey(viewId) >= 0) return;
        mDingRtcViews.put(viewId, view);
    }

    public void removeView(int viewId) {
        mDingRtcViews.remove(viewId);
    }

    public void enterRoom(Map<String, String> params) {
        DingRtcAuthInfo mAuthInfo = new DingRtcAuthInfo();
        mAuthInfo.userId = params.get("meeting_user_id");
        mAuthInfo.token = params.get("meeting_token");
        mAuthInfo.appId = params.get("meeting_app_id");
        mAuthInfo.channelId = params.get("meeting_channel_id");
        mAuthInfo.gslbServer = params.get("meeting_gslb");
        String userName = params.get("meeting_user_name");
        int ret = mRtcEngine.joinChannel(mAuthInfo, userName);
        if (ret != 0) {
            onError(ret, "enter room failure");
        }
    }

    public void setLogLevel(int value) {
        for(DingRtcEngine.DingRtcLogLevel level : DingRtcEngine.DingRtcLogLevel.values()) {
            if(level.getValue() == value) {
                DingRtcEngine.setLogLevel(level);
                break;
            }
        }
    }

    public void leaveRoom() {
        mRtcEngine.stopPreview();
        mRtcEngine.publishLocalAudioStream(false);
        mRtcEngine.publishLocalVideoStream(false);
        mRtcEngine.leaveChannel();
    }

    public void startLocalPreview(boolean isFrontCamera, int viewId) {
        DingRtcView view = mDingRtcViews.get(viewId);
        if(view == null) {
            Log.e(TAG, "startLocalPreview: view is null.viewId=" + viewId);
            return;
        }

        DingRtcEngine.DingEngineCameraCapturerConfiguration configuration = new DingRtcEngine.DingEngineCameraCapturerConfiguration();
        configuration.cameraDirection = isFrontCamera ?
                DingRtcEngine.DingRtcCameraDirection.CAMERA_FRONT :
                DingRtcEngine.DingRtcCameraDirection.CAMERA_REAR;
        mRtcEngine.setCameraCapturerConfiguration(configuration);
        mRtcEngine.setLocalViewConfig(view.mCanvas, DingRtcVideoTrackCamera);
        mRtcEngine.startPreview();
    }

    public void enableSpeakerphone(boolean enable) {
        mRtcEngine.enableSpeakerphone(enable);
    }
    public void muteLocalAudio(boolean mute) {
        mRtcEngine.muteLocalAudio(mute);
    }
    public void enableLocalVideo(boolean enable) {
        mRtcEngine.enableLocalVideo(enable);
    }

    public void stopLocalPreview() {
        mRtcEngine.stopPreview();
    }

    public void switchCamera() {
        mRtcEngine.switchCamera();
    }

    public void startRemoteView(String userId, int viewId) {
        DingRtcView view = mDingRtcViews.get(viewId);
        if(view == null) {
            Log.e(TAG, "startRemoteView: view is null.viewId=" + viewId);
            return;
        }
        mRtcEngine.setRemoteViewConfig(view.mCanvas, userId, DingRtcEngine.DingRtcVideoTrack.DingRtcVideoTrackCamera);
    }

    // 更新远端用户视频的视图
    public void updateRemoteVideoRender(DingRtcEngine.DingRtcVideoCanvas canvas, String uid, boolean isScreen) {
        if(isScreen) {
            mRtcEngine.setRemoteViewConfig(null, uid, DingRtcVideoTrackScreen);
            mRtcEngine.setRemoteViewConfig(canvas, uid, DingRtcVideoTrackScreen);
        } else {
            mRtcEngine.setRemoteViewConfig(null, uid, DingRtcVideoTrackCamera);
            mRtcEngine.setRemoteViewConfig(canvas, uid, DingRtcVideoTrackCamera);
        }
    }

    // 更新本地用户视频的视图
    public void updateLocalVideoRender(DingRtcEngine.DingRtcVideoCanvas canvas, boolean isScreen) {
        if(isScreen) {
            mRtcEngine.setLocalViewConfig(null, DingRtcVideoTrackScreen);
            mRtcEngine.setLocalViewConfig(canvas, DingRtcVideoTrackScreen);
        } else{
            mRtcEngine.setLocalViewConfig(null, DingRtcVideoTrackCamera);
            mRtcEngine.setLocalViewConfig(canvas, DingRtcVideoTrackCamera);
        }
    }

    public int snapshotVideo(String uid, boolean isScreen, String path){
        return mRtcEngine.snapshotVideo(uid, isScreen ? DingRtcVideoTrackScreen : DingRtcVideoTrackCamera, path);
    }
}
